home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Info-Mac 3
/
Info_Mac_1994-01.iso
/
Development
/
General
/
Controls GH
/
Slider Control GH
/
Slider.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-22
|
18KB
|
659 lines
/************** Slider.c v1.0 *********
******* code for a slider type control CDEF
*******©1993 Glenn R. Howes
******* all rights reserved *****/
// #include "Slider.h" included in the prefix option
#include "utilities.h"
pascal long main(short variation, ControlHandle me,
short msg, long param)
{
long result = 0L;
switch (msg)
{
case testCntl: // determine if mouse down is in control
result = TestMe(me, HiWord(param), LoWord(param));
break;
case calcCRgns: // 24-bit means of requesting shape of control or part
result = CalcStripRegion(me, (RgnHandle)param);
break;
case initCntl: // 1st message, allocate private data
InitMe(me);
break;
case dispCntl: // last message, dispose private data
if ((*me)->contrlData)
DisposeHandle((*me)->contrlData);
break;
case posCntl: // given new point (and old point from the thumbCntl msg)
// set the controls new value
PositionMe(me, HiWord(param), LoWord(param));
break;
case thumbCntl: // request for info for use in dragging thumb outline
// also gives point at which drag starts
ProvideDragInfo(me, (ThumbInfo*)param);
break;
case dragCntl: // we aren't doing any custom tracking ignore
break;
case autoTrack: // we aren't doing any custom tracking ignore
// result = TrackMe(me, LoWord(param));
break;
case calcCntlRgn: // 32-bit clean message asking for whole cntl region
CalcRegion( me, (RgnHandle)param, FALSE);
result = 1L;
break;
case calcThumbRgn: // 32-bit clean message asking for shape of thumb
result = CalcRegion( me, (RgnHandle)param, TRUE);
result = 1L;
break;
case drawCntl: // draw control or part of control
DrawMe(me, LoWord(param));
break;
}
return (result);
}
/******************* ProvideDragInfo ***********
**** a mouse down has occurred in the thumb and we are
**** asked to proide information used by the toolbox routine
**** DragGrayRgn to confine the drag to a given rectangle
**** the limit rect is the rect in which the region will move
**** the slop rect is the rect in which the mouse can be and the
**** gray outline will still be visible.
**** Notice that I'm taking into account the position within the
**** thumb so that the region doesn't go beyond the control****/
void ProvideDragInfo(ControlHandle me, ThumbInfo *param)
{
Rect ctlRect, thumbRect;
PrivateHandle privData;
Point entry;
privData = (PrivateHandle)(*me)->contrlData;
// the original mousedown point is stored in the top,left corner of
// the thumbinfo's limitRect field
entry.h = param->limitRect.left;
entry.v = param->limitRect.top;
if (privData)
{
(*privData)->entryPoint.h = entry.h;
(*privData)->entryPoint.v = entry.v;
}
CopyRect(&(*me)->contrlRect, &ctlRect);
CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
if ((ctlRect.bottom - ctlRect.top) // if we are a vertical control
>= (ctlRect.right - ctlRect.left))
{
ctlRect.bottom -= (thumbRect.bottom - entry.v);
ctlRect.top += (entry.v - thumbRect.top);
CopyRect(&ctlRect, ¶m->limitRect);
param->axis = 2; // confine to vertical
}
else // if we are a horizontal control
{
ctlRect.right -= (thumbRect.right - entry.h) -1;
ctlRect.left += (entry.h - thumbRect.left);
CopyRect(&ctlRect, ¶m->limitRect);
param->axis = 1; // confine to horizontal
}
InsetRect(&ctlRect, -5, -5); // make slop bigger than ctl rect
CopyRect(&ctlRect, ¶m->slopRect);
}
/************ PositionMe *************
******** I've been dragged, with the sequence
****** TestMe, ProvideDragInfo, and now PositionMe
****** so the delta values are changes from the original mousedown *****/
void PositionMe(ControlHandle me, short deltaV, short deltaH)
{
Point newPoint;
MapValue2Point(me, (*me)->contrlValue, &newPoint);
newPoint.v += deltaV;
newPoint.h += deltaH;
MapPt2Value(me, &newPoint, &(*me)->contrlValue);
DrawMe(me, 0);
}
/************ MapPt2Value *****************
***** given a point within the control, map it to a control value
******/
void MapPt2Value(ControlHandle me, Point *aPoint, short *value)
{
Rect ctlRect;
short width, height, thumbLen, halfThumb;
long min, max, locValue;
CopyRect(&(*me)->contrlRect, &ctlRect);
min = (*me)->contrlMin;
max = (*me)->contrlMax;
width = ctlRect.right - ctlRect.left;
height = ctlRect.bottom - ctlRect.top;
thumbLen = CalcThumbLen(&ctlRect);
halfThumb = thumbLen /2;
if (width > height)
{
ctlRect.right -= halfThumb;
ctlRect.left += halfThumb;
width -= thumbLen;
if (ctlRect.right < aPoint->h) aPoint->h = ctlRect.right;
else if (ctlRect.left > aPoint->h) aPoint->h = ctlRect.left;
locValue = min + ((max-min)*(aPoint->h-ctlRect.left))/width;
}
else
{
ctlRect.bottom -= halfThumb;
ctlRect.top += halfThumb;
height -= thumbLen;
if (ctlRect.bottom < aPoint->v) aPoint->v = ctlRect.bottom;
else if (ctlRect.top > aPoint->v) aPoint->v = ctlRect.top;
locValue = min + ((max-min)*(ctlRect.bottom-aPoint->v))/height;
}
*value = locValue;
}
/*********** MapValue2Point *********
******* given a control value, convert it to a point within
******* the control corresponding to where the center of the thumb
******* must be **********/
void MapValue2Point(ControlHandle me, short value, Point *aPoint)
{
Rect ctlRect;
long width, height;
long min, max;
short thumbLen, halfThumb;
CopyRect(&(*me)->contrlRect, &ctlRect);
min = (*me)->contrlMin;
max = (*me)->contrlMax;
thumbLen = CalcThumbLen(&ctlRect);
halfThumb = thumbLen /2;
width = ctlRect.right - ctlRect.left;
height = ctlRect.bottom - ctlRect.top;
if (value > max)
value = max;
else if (value < min)
value = min;
if (width > height) // horizontal control
{
width -= thumbLen;
aPoint->h = ctlRect.left + halfThumb + (width*value)/(max-min);
aPoint->v = ctlRect.top + height/2;
}
else
{
height -= thumbLen;
aPoint->v = ctlRect.bottom - halfThumb -(height * value)/(max-min);
aPoint->h = ctlRect.left + width/2;
}
}
/************* CalcStripRegion *******
******* when in 24-bit mode, we will get a region handle whose
******* 31st bit is used to indicate if the app wants the region
******* of the thumb (on) or the whole control (off).
******* We are supposed to strip off the bit and return the
******* calculated region ******/
long CalcStripRegion(ControlHandle me, RgnHandle theRegion)
{
char calcThumb;
if (Using32Bit()) // WHY IS THIS GETTING CALLED¿
{
return (CalcRegion(me, theRegion, FALSE));
}
else
{
calcThumb = (long)theRegion >> 31L; // getting high bit, on = calc thumb
theRegion = (RgnHandle)(0x7FFFFFFFL & (long)theRegion);
// stripping out high bit only see tech note “joy of 32 bit clean”
return (CalcRegion(me, theRegion, calcThumb)); // calc the region
}
}
/*************** CalcRegion ******
******* figure the region of the control, or the thumb if the
******* calcThumb parameter is non-zero **********/
long CalcRegion(ControlHandle me, RgnHandle theRegion, char calcThumb)
{
RgnHandle myRegion;
Rect ctlRect, thumbRect;
short diameter;
myRegion = NewRgn();
if (myRegion)
{
OpenRgn();
CopyRect(&(*me)->contrlRect, &ctlRect);
diameter = CalcRounding(&ctlRect);
if (calcThumb)
{
CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
FrameRoundRect(&thumbRect, diameter,diameter);
}
else
{
FrameRoundRect(&ctlRect, diameter, diameter);
}
CloseRgn(myRegion);
InsetRgn(myRegion, -1, -1); // make it a little bigger to take into account
// width of lines
UnionRgn(theRegion, myRegion, theRegion);
DisposeRgn(myRegion);
}
return ((long)theRegion);
}
/************ TestMe ****************
******* is the point within the control, and if so,
******* what part, there are 3 parts: thumb, pageup,
pagedown **********/
long TestMe(ControlHandle me, short v, short h)
{
Point testPoint;
long result = 0L;
Rect ctlRect, whiteRect, grayRect, roundThumb;
testPoint.h = h; testPoint.v = v;
if(PtInRect(testPoint, &(*me)->contrlRect) && (*me)->contrlHilite < 255)
// quick determination of (mouse in rect and control undimmed)
{
CopyRect(&(*me)->contrlRect, &ctlRect);
CalcGrayRect(me, &grayRect, &whiteRect);
CalcThumbRects(me,(*me)->contrlValue, &roundThumb);
if (PtInRect(testPoint, &roundThumb))
{
result = inThumb;
}
else if (PtInRect(testPoint, &grayRect))
{
result = inPageUp;
}
else
{
result = inPageDown;
}
}
return (result);
}
/*************** DrawMe **********
******* Draw the control or the control's thumb *****/
void DrawMe(ControlHandle me, short part)
{
Rect grayRect, whiteRect, thumbRect, tempRect;
PenState oldState;
PrivateHandle privData;
RgnHandle oldRegion = 0L, thumbRegion = 0L, ctlRegion =0L;
short diameter;
GetPenState(&oldState);
PenNormal();
privData = (PrivateHandle)(*me)->contrlData;
CalcGrayRect(me, &grayRect, &whiteRect);
CalcThumbRects(me, (*me)->contrlValue, &thumbRect);
switch (part)
{
case 255: // change in dimming
EraseRect(&grayRect);
case 0: // draw whole thing
EraseRect(&whiteRect);
DrawMyFrame(me,&grayRect);
DrawMyIndicator(me, &thumbRect);
break;
case 129: // redraw generic indicator
// I'm using the regions to stop the flashing of drawing
// the gray rect and then drawing the white thumb over it
oldRegion = NewRgn();
thumbRegion = NewRgn();
ctlRegion = NewRgn();
if (ctlRegion && thumbRegion && oldRegion && privData)
{
diameter = CalcRounding(&(*me)->contrlRect);
GetClip(oldRegion);
CopyRect(&thumbRect, &tempRect);
// InsetRect(&tempRect, -2,-2);
OpenRgn();
FrameRoundRect(&(*me)->contrlRect, diameter, diameter);
CloseRgn(ctlRegion);
OpenRgn();
FrameRoundRect(&thumbRect, diameter, diameter);
CloseRgn(thumbRegion);
XorRgn(ctlRegion, thumbRegion, thumbRegion);
SetClip(thumbRegion);
CleanOldThumb(me, &thumbRect);
SetClip(ctlRegion);
DrawMyIndicator(me, &thumbRect);
SetClip(oldRegion);
}
else // we had a memory allocation problem, draw whole thing
{
EraseRect(&whiteRect);
DrawMyFrame(me,&grayRect);
DrawMyIndicator(me, &thumbRect);
}
if (thumbRegion) DisposeRgn(thumbRegion);
if (ctlRegion) DisposeRgn(ctlRegion);
if (oldRegion) DisposeRgn(oldRegion);
break;
default:
case inPageUp:
case inPageDown:
break;
}
if (privData)
(*privData)->oldValue = (*me)->contrlValue;
SetPenState(&oldState);
}
/*************** CleanOldThumb *************
***** We've gotten a message to draw the thumb, which
***** implies we have to eradicate the old thumb *******/
void CleanOldThumb(ControlHandle me, Rect *thumbRect)
{
PrivateHandle privData;
short oldValue, currValue;
short diameter;
Rect grayRect, ctlRect, oldThumb, whiteRect;
Boolean upAndDown;
Pattern grayPattern;
privData = (PrivateHandle)(*me)->contrlData; // privData has already been tested
currValue = (*me)->contrlValue;
oldValue = (*privData)->oldValue;
//if (currValue == oldValue) return;
(*me)->contrlValue = oldValue;
CalcGrayRect(me, &grayRect, &whiteRect);
(*me)->contrlValue = currValue;
CopyRect(&(*me)->contrlRect, &ctlRect);
diameter = CalcRounding(&ctlRect);
upAndDown = ((ctlRect.right - ctlRect.left) <= (ctlRect.bottom - ctlRect.top));
CalcThumbRects(me, oldValue, &oldThumb);
GetIndPattern(grayPattern, 0, 1);// black
PenPat(&grayPattern);
if (oldValue > currValue)
{
if (upAndDown)
{
oldThumb.bottom = thumbRect->bottom;
}
else
{
oldThumb.left = thumbRect->left;
}
FillRoundRect(&oldThumb, diameter, diameter, &grayPattern);
}
else
{
if (upAndDown)
{
oldThumb.top = thumbRect->top;
}
else
{
oldThumb.right = thumbRect->right;
}
EraseRoundRect(&oldThumb, diameter, diameter);
}
FrameRoundRect(&ctlRect, diameter, diameter);
}
/********** DrawMyIndicator ************
******* Draw the thumb, the thumbRect must be previously
******* calculated ******/
void DrawMyIndicator(ControlHandle me, Rect *thumbRect)
{
Rect ctlRect;
Boolean useColorQD, dimmed = FALSE;
RGBColor newColor, oldColor;
Pattern grayPattern;
Boolean upAndDown;
short diameter;
PrivateHandle privData;
privData = (PrivateHandle)(*me)->contrlData;
if ((*me)->contrlMin >= (*me)->contrlMax) dimmed = TRUE;
if ((*me)->contrlHilite == 255) dimmed = TRUE;
if (!dimmed)
{
CopyRect(&(*me)->contrlRect, &ctlRect);
diameter = CalcRounding (&ctlRect);
// calculate the rectangles used in drawing
useColorQD = UseColorQD(me, thumbRect);
// start actual drawing
if(useColorQD && privData)
{
GetForeColor(&oldColor);
RGBForeColor(&(*privData)->thumbColor); // real medium gray
GetIndPattern(grayPattern, 0, 1);// standard black for fill
FillRoundRect(thumbRect, diameter, diameter, &grayPattern);
RGBForeColor(&oldColor);
}
else
{
GetIndPattern(grayPattern, 0, 4);// standard gray for fill
FillRoundRect(thumbRect, diameter, diameter, &grayPattern);
}
FrameRoundRect(thumbRect, diameter, diameter);
}
}
/***************** CalcThumbRects ******
**** should be CalcThumbRect, just figure what the bounding rect of
*** the thumb should be given the value *******/
void CalcThumbRects(ControlHandle me, short value,
Rect *roundThumb)
{
long width, height, thumbLen;
Point valuePoint;
Rect ctlRect;
CopyRect(&(*me)->contrlRect, &ctlRect);
CopyRect(&ctlRect, roundThumb);
height = ctlRect.bottom - ctlRect.top;
width = ctlRect.right - ctlRect.left;
MapValue2Point(me, value, &valuePoint);
thumbLen = CalcThumbLen(&ctlRect);
// calculate the rectangles used in drawing
if (height >= width)
{
roundThumb->top = valuePoint.v - thumbLen/2;
roundThumb->bottom = roundThumb->top+thumbLen;
}
else
{
roundThumb->right = valuePoint.h + thumbLen/2;
roundThumb->left = roundThumb->right - thumbLen;
}
}
/********** CalcThumbLen *********
**** figure how high or wide the thumb should be (given
**** that some moron might have made the control too small ***/
short CalcThumbLen(Rect *ctlRect)
{
short height, width;
short result;
height = ctlRect->bottom - ctlRect->top;
width = ctlRect->right - ctlRect->left;
if (width > height)
{
result = (width > 20)?20:width;
}
else
{
result = (height > 20)?20:height;
}
return (result);
}
/********* DrawMyFrame **********
******* Draw the black portion of the control (pageup)
******* and frame the whole thing ********/
void DrawMyFrame(ControlHandle me, Rect *grayRect)
{
Rect ctlRect;
Boolean useColorQD, dimmed = FALSE;
RGBColor newColor, oldColor;
Pattern grayPattern;
PrivateHandle privData;
short min, max, diameter;
privData = (PrivateHandle)(*me)->contrlData;
CopyRect(&(*me)->contrlRect, &ctlRect);
useColorQD = UseColorQD(me, &ctlRect);
min = (*me)->contrlMin;
max = (*me)->contrlMax;
diameter = CalcRounding (&ctlRect);
if (min >= max)
{
dimmed = TRUE;
}
if ((*me)->contrlHilite == 255) dimmed = TRUE;
if (!dimmed)
{
GetIndPattern(grayPattern, 0, 1);// standard black for frame and top region
FillRoundRect(grayRect,diameter, diameter, &grayPattern);
PenPat(&grayPattern);
}
if(useColorQD && privData)
{
GetForeColor(&oldColor);
RGBForeColor(&(*privData)->frameColor);
FrameRoundRect(&ctlRect, diameter, diameter);
RGBForeColor(&oldColor);
}
else
FrameRoundRect(&ctlRect, diameter, diameter);
}
/*********** CalcGrayRect
***** figure out the rectangle which enclose the pageup and pagedown
***** parts of the control (they meet in the middle of the thumb) ***/
void CalcGrayRect(ControlHandle me, Rect *grayRect, Rect *whiteRect)
{
long height, width, value, max, min;
Point valuePoint;
short thumbLen, halfThumb;
value = (*me)->contrlValue;
min = (*me)->contrlMin;
max = (*me)->contrlMax;
if (value > max) // too big, who let this in?
value = max;
else if (value < min) // too small
value = min;
MapValue2Point(me,value, &valuePoint);
CopyRect(&(*me)->contrlRect, grayRect);
CopyRect(grayRect, whiteRect);
thumbLen = CalcThumbLen(grayRect);
halfThumb = thumbLen /2;
width = grayRect->right - grayRect->left;
height = grayRect->bottom - grayRect->top;
if (width > height) // we are going side to side
{
grayRect->left = valuePoint.h - halfThumb;
whiteRect->right = valuePoint.h;
}
else
{ // halfThumb is because quickdraw sort of bales out
// when round rects are small
grayRect->bottom = valuePoint.v + halfThumb;
whiteRect->top = valuePoint.v;
}
}
/******* CalcRounding *******
****** are we big enough to use round rectangles
if so use 16 diameter rounding, if not use square corners ****/
short CalcRounding(Rect *ctlRect)
{
short width, height;
width = ctlRect->right - ctlRect->left;
height = ctlRect->bottom - ctlRect->top;
if (width > height)
{
if (width > 64)
return (16);
}
else
{
if (height > 64)
return (16);
}
return (0);
}
/******** InitMe ********
****** allocate my global memory, test for color and load color table
****** information ****/
void InitMe(ControlHandle me)
{
PrivateHandle privDataH;
AuxCtlHandle acHndl;
CCTabHandle tableH;
short tabLen;
RGBColor *tempColor;
privDataH = (PrivateHandle)NewHandleClear(sizeof(Private));
if (privDataH)
{
if ((*privDataH)->useColorQD = TestForColor())
{// we are using color, find the highlight color
tempColor = &(*privDataH)->frameColor;
tempColor->red = tempColor->blue = tempColor->green = 0; // black
tempColor = &(*privDataH)->thumbColor;
tempColor->blue = tempColor->green = tempColor->red = 30583; // gray
GetAuxCtl(me, &acHndl);
if (acHndl)
{
tableH = (*acHndl)->acCTable;
tabLen = (*tableH)->ctSize;
while(tabLen >= 0)
{
if ((*tableH)->ctTable[tabLen].value == cFrameColor)
{
BlockMove(&(*tableH)->ctTable[tabLen].rgb,
&(*privDataH)->frameColor, sizeof(RGBColor));
}
/* else if ((*tableH)->ctTable[tabLen].value == cThumbColor)
{
BlockMove(&(*tableH)->ctTable[tabLen].rgb,
&(*privDataH)->thumbColor, sizeof(RGBColor));
} */
tabLen--;
}
}
}
// we need to know if we can call GetDeviceList to tell whether
// or not our control is on a deep color screen
(*privDataH)->devicesAvailable = TrapAvailable(0xAA29);
(*privDataH)->oldValue = (*me)->contrlValue;
}
(*me)->contrlData = (Handle)privDataH;
}